#include "SerialPort_SerialPortOutputStream.h"
#include "jni_utile.h"
#include "SerialPortFactory.h"
#include <boost\scoped_array.hpp>
#include <boost\asio\write.hpp>
#include <boost\bind.hpp>

extern JavaVM* g_jvm;
extern boost::shared_ptr<SerialPortFactory> serialPortFactory;

/*
* Class:     SerialPort_SerialPortOutputStream
* Method:    write
* Signature: (J[BII)V
*/
JNIEXPORT void JNICALL Java_SerialPort_SerialPortOutputStream_write
(JNIEnv *penv, jobject obj, jlong fd, jbyteArray bytes, jint off, jint len) {
	if (fd < 0) {
		throw_serial_exception(penv, FD_INVALID);
		return;
	}
	else {
		SerialPortInfoPtr pserialInfo = serialPortFactory->get_serial_info(fd);
		boost::scoped_array<jbyte> contect(new jbyte[len]);

		if (pserialInfo == NULL) {
			throw_serial_exception(penv, PORT_NOT_OPENED);
			return;
		}
		else {
			boost::system::error_code ec;

			penv->GetByteArrayRegion(bytes, off, len, contect.get());

			if (penv->ExceptionOccurred()) {
				return ;
			}

			serial_port_ptr pserial_port = pserialInfo->get_serial_port_ptr();

			boost::asio::write(*pserial_port.get(), boost::asio::buffer(contect.get(), len), ec);

			if (ec.value() != boost::system::errc::success) {
				throw_serial_exception(penv, ec.message().c_str());
				return;
			}

		}
	}

}

/*
* Class:     SerialPort_SerialPortOutputStream
* Method:    writeAsync
* Signature: (J[BIILSerialPort/TranseFinish;)V
*/
JNIEXPORT void JNICALL Java_SerialPort_SerialPortOutputStream_writeAsync
(JNIEnv *penv, jobject obj, jlong fd, jbyteArray bytes, jint off, jint len, jobject handle) {
	if (fd > 0) {
		int len = penv->GetArrayLength(bytes);
		SerialPortInfoPtr pserialInfo = serialPortFactory->get_serial_info(fd);
		boost::shared_array<jbyte> contect(new jbyte[len]);

		if (pserialInfo == NULL) {
			call_trans_handle(penv, handle, boost::system::errc::make_error_code(boost::system::errc::identifier_removed), 0);
		}
		else {
			int size_send = 0;
			jobject global_handle = penv->NewGlobalRef(handle);

			if (global_handle != NULL) {
				penv->GetByteArrayRegion(bytes, 0, len, contect.get());

				boost::asio::async_write(*pserialInfo->get_serial_port_ptr().get(),
					boost::asio::buffer((const void*)contect.get(), len),
					boost::bind(warp_trans_handle, _1, _2, g_jvm, global_handle, contect));
			}
			else {
				call_trans_handle(penv, handle, boost::system::errc::make_error_code(boost::system::errc::not_enough_memory), 0);
			}
		}
	}
	else {
		call_trans_handle(penv, handle, boost::system::errc::make_error_code(boost::system::errc::bad_file_descriptor), 0);
	}
}